package com.scvtc.aspect.log;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.scvtc.annotation.log.ScvtcLog;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * @Description: 博客日志信息
 * @Author: yiFei
 * @date: 2022/3/22 13:49
 */
@Aspect
@Component
public class ScvtcAspect {

    @Autowired
    private ObjectMapper objectMapper;

    private static final Logger log = LoggerFactory.getLogger(ScvtcLog.class);

    /**
     * 打印控制层信息
     */
    @Pointcut("execution(* com.scvtc.controller..*.*(..)) && !execution(* com.scvtc.controller..*.export*(..)) && !execution(* com.scvtc.controller..*.file*(..))")
    public void cutController() {
    }

    /**
     * 可以使用ApiOperation
     */
    @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
    public void ApiOperation() {
    }

    @Pointcut("@annotation(com.scvtc.annotation.log.ScvtcLog)")
    public void ScvtcLog() {
    }

    @Around("cutController()")
    public Object cutController(ProceedingJoinPoint joinPoint) throws Throwable {
        // 请求参数
        Object[] args = joinPoint.getArgs();
        // 返回结果
        Object proceed = null;
        try {
            beforeHandler(joinPoint);
            proceed = joinPoint.proceed(args);
            afterHandler(proceed);
        } finally {
            log.info("=========END=========" + System.lineSeparator());
        }
        return proceed;
    }

    @Around("ScvtcLog()")
    public Object logScvtc(ProceedingJoinPoint joinPoint) throws Throwable {
        // 请求参数
        Object[] args = joinPoint.getArgs();
        // 返回结果
        Object proceed = null;
        try {
            beforeHandler(joinPoint);
            ScvtcLogHandler(joinPoint);
            proceed = joinPoint.proceed(args);
            afterHandler(proceed);
        } finally {
            log.info("=========END=========" + System.lineSeparator());
        }
        return proceed;
    }

    /**
     * 打印自定义注解
     *
     * @param joinPoint
     */
    private void ScvtcLogHandler(ProceedingJoinPoint joinPoint) {
        ScvtcLog blogLog = getScvtcLog(joinPoint);
        log.info("SCVTC LOG            :{}", blogLog.getClass().getSimpleName());
        log.info("MODULE              :{}", blogLog.module());
        log.info("DESCRIBE            :{}", blogLog.describe());
    }

    /**
     * 获取自定义注解
     *
     * @param joinPoint
     * @return
     */
    private ScvtcLog getScvtcLog(ProceedingJoinPoint joinPoint) {
        // 获取方法
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 获取自定义注解
        // 返回自定义注解
        return methodSignature.getMethod().getAnnotation(ScvtcLog.class);
    }

    /**
     * 打印结果
     *
     * @param proceed
     * @throws JsonProcessingException
     */
    private void afterHandler(Object proceed) throws JsonProcessingException {
        log.info("RESPONSE            :{}", objectMapper.writeValueAsString(proceed));
    }

    /**
     * 打印基本信息
     *
     * @param joinPoint
     * @throws JsonProcessingException
     */
    private void beforeHandler(ProceedingJoinPoint joinPoint) throws JsonProcessingException {
        // 请求 信息
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        // 请求方法
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

        log.info("========START========");
        log.info("URL                 :{}", request.getRequestURL());
        log.info("USER                :{}", SecurityContextHolder.getContext().getAuthentication().getName());
        log.info("Host                :{}", request.getRemoteHost());
        log.info("HTTP METHOD         :{}", request.getMethod());
        log.info("CLASS METHOD        :{}.{}", methodSignature.getDeclaringTypeName(), methodSignature.getMethod().getName());
        log.info("ARGS                :{}", objectMapper.writeValueAsString(joinPoint.getArgs()));
    }
}
